#!/bin/bash

# Minecraft 服务器更新工具函数模块
# 描述：包含日志记录、备份、通知等通用功能函数

# ======= 配置加载函数 =======
# 检查是否安装了jq
check_jq() {
    if ! command -v jq > /dev/null; then
        echo "错误: 未找到jq命令，请安装jq工具"
        echo "在Debian/Ubuntu上运行: sudo apt-get install jq"
        echo "在CentOS/RHEL上运行: sudo yum install jq"
        exit 1
    fi
}

# 从JSON配置文件加载配置
load_config() {
    local config_file="$1"
    
    # 检查配置文件是否存在
    if [ ! -f "$config_file" ]; then
        echo -e "\e[1;31m错误: 配置文件 $config_file 不存在\e[0m"
        # 使用默认值
        LOG_FILE="/var/log/minecraft_updater.log"
        TEMP_DIR="/tmp/minecraft_updater"
        BACKUP_ENABLED="true"
        BACKUP_RETENTION_DAYS="7"
        BACKUP_DIR="/opt/minecraft/backups"
        USER_AGENT="Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36"
        # 先初始化，确保日志文件和临时目录存在
        init
        exit 1
    fi
    
    # 检查jq是否已安装
    check_jq
    
    # 加载全局配置
    LOG_FILE=$(jq -r '.global.log_file' "$config_file")
    TEMP_DIR=$(jq -r '.global.temp_dir' "$config_file")
    BACKUP_ENABLED=$(jq -r '.global.backup.enabled' "$config_file")
    BACKUP_RETENTION_DAYS=$(jq -r '.global.backup.retention_days' "$config_file")
    BACKUP_DIR=$(jq -r '.global.backup.dir' "$config_file")
    USER_AGENT=$(jq -r '.global.user_agent' "$config_file")
    
    # 加载更新计划配置
    UPDATE_SCHEDULE=$(jq -r '.global.update.schedule' "$config_file")
    UPDATE_SCHEDULE_TYPE=$(jq -r '.global.update.schedule_type' "$config_file")
    UPDATE_INTERVAL_HOURS=$(jq -r '.global.update.interval_hours' "$config_file")
    UPDATE_SPECIFIC_DAYS=$(jq -r '.global.update.specific_days[]' "$config_file" 2>/dev/null | tr '\n' ',' | sed 's/,$//')
    UPDATE_ACTIVE=$(jq -r '.global.update.active' "$config_file")
    
    # 加载Java版配置
    JAVA_SERVER_DIR=$(jq -r '.java.server_dir' "$config_file")
    JAVA_SERVER_TYPE=$(jq -r '.java.server_type' "$config_file")
    JAVA_VERSION=$(jq -r '.java.version' "$config_file")
    JAVA_START_COMMAND=$(jq -r '.java.start_command' "$config_file")
    JAVA_SESSION_NAME=$(jq -r '.java.session_name' "$config_file")
    JAVA_AUTO_RESTART=$(jq -r '.java.auto_restart' "$config_file")
    
    # 加载Java版API URL
    JAVA_API_URL=$(jq -r '.java.api_url' "$config_file")
    JAVA_DOWNLOAD_URL=$(jq -r '.java.download_url' "$config_file")
    
    # 加载基岩版配置
    BEDROCK_SERVER_DIR=$(jq -r '.bedrock.server_dir' "$config_file")
    BEDROCK_VERSION=$(jq -r '.bedrock.version' "$config_file")
    BEDROCK_START_COMMAND=$(jq -r '.bedrock.start_command' "$config_file")
    BEDROCK_SESSION_NAME=$(jq -r '.bedrock.session_name' "$config_file")
    BEDROCK_AUTO_RESTART=$(jq -r '.bedrock.auto_restart' "$config_file")
    
    # 加载基岩版API URL
    BEDROCK_DOWNLOAD_PAGE_URL=$(jq -r '.bedrock.api_url' "$config_file")
    BEDROCK_DOWNLOAD_BASE_URL=$(jq -r '.bedrock.download_url' "$config_file")
    
    # 加载通知配置
    ENABLE_NOTIFICATIONS=$(jq -r '.notifications.enabled' "$config_file")
    NOTIFICATION_METHOD=$(jq -r '.notifications.method' "$config_file")
    
    # 加载Telegram配置
    TELEGRAM_BOT_TOKEN=$(jq -r '.notifications.telegram.bot_token' "$config_file")
    TELEGRAM_CHAT_ID=$(jq -r '.notifications.telegram.chat_id' "$config_file")
    TELEGRAM_API_URL=$(jq -r '.notifications.telegram.api_url' "$config_file")
    
    # 加载Discord配置
    DISCORD_WEBHOOK=$(jq -r '.notifications.discord.webhook' "$config_file")
    
    # 加载邮件配置
    EMAIL_TO=$(jq -r '.notifications.email.to' "$config_file")
    EMAIL_FROM=$(jq -r '.notifications.email.from' "$config_file")
    EMAIL_SUBJECT=$(jq -r '.notifications.email.subject' "$config_file")
    
    # 检查配置是否为空或为null，设置默认值
    if [ "$LOG_FILE" = "null" ] || [ -z "$LOG_FILE" ]; then
        LOG_FILE="/var/log/minecraft_updater.log"
    fi
    
    if [ "$TEMP_DIR" = "null" ] || [ -z "$TEMP_DIR" ]; then
        TEMP_DIR="/tmp/minecraft_updater"
    fi
    
    if [ "$BACKUP_DIR" = "null" ] || [ -z "$BACKUP_DIR" ]; then
        BACKUP_DIR="/opt/minecraft/backups"
    fi
    
    if [ "$BACKUP_ENABLED" = "null" ] || [ -z "$BACKUP_ENABLED" ]; then
        BACKUP_ENABLED="true"
    fi
    
    if [ "$BACKUP_RETENTION_DAYS" = "null" ] || [ -z "$BACKUP_RETENTION_DAYS" ]; then
        BACKUP_RETENTION_DAYS="7"
    fi
    
    if [ "$USER_AGENT" = "null" ] || [ -z "$USER_AGENT" ]; then
        USER_AGENT="Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36"
    fi
    
    # 导出配置变量，使其对其他脚本可见
    export LOG_FILE TEMP_DIR BACKUP_ENABLED BACKUP_RETENTION_DAYS BACKUP_DIR USER_AGENT
    export UPDATE_SCHEDULE UPDATE_SCHEDULE_TYPE UPDATE_INTERVAL_HOURS UPDATE_SPECIFIC_DAYS UPDATE_ACTIVE
    export JAVA_SERVER_DIR JAVA_SERVER_TYPE JAVA_VERSION JAVA_START_COMMAND JAVA_SESSION_NAME JAVA_AUTO_RESTART
    export JAVA_API_URL JAVA_DOWNLOAD_URL
    export BEDROCK_SERVER_DIR BEDROCK_VERSION BEDROCK_START_COMMAND BEDROCK_SESSION_NAME BEDROCK_AUTO_RESTART
    export BEDROCK_DOWNLOAD_PAGE_URL BEDROCK_DOWNLOAD_BASE_URL
    export ENABLE_NOTIFICATIONS NOTIFICATION_METHOD
    export TELEGRAM_BOT_TOKEN TELEGRAM_CHAT_ID TELEGRAM_API_URL DISCORD_WEBHOOK EMAIL_TO EMAIL_FROM EMAIL_SUBJECT
    
    # 初始化日志文件和临时目录
    init
}

# ======= 日志函数 =======
# 记录信息日志
log_info() {
    local message="[INFO] $(date '+%Y-%m-%d %H:%M:%S') - $1"
    echo -e "\e[32m$message\e[0m"
    echo "$message" >> "$LOG_FILE"
}

# 记录警告日志
log_warning() {
    local message="[WARNING] $(date '+%Y-%m-%d %H:%M:%S') - $1"
    echo -e "\e[33m$message\e[0m"
    echo "$message" >> "$LOG_FILE"
}

# 记录错误日志
log_error() {
    local message="[ERROR] $(date '+%Y-%m-%d %H:%M:%S') - $1"
    echo -e "\e[31m$message\e[0m"
    echo "$message" >> "$LOG_FILE"
}

# ======= 备份函数 =======
# 创建服务器备份
create_backup() {
    local server_dir="$1"
    local server_type="$2"
    
    if [ "$BACKUP_ENABLED" != "true" ]; then
        log_info "备份功能已禁用，跳过备份步骤"
        return 0
    fi
    
    # 检查备份目录是否存在，不存在则创建
    if [ ! -d "$BACKUP_DIR" ]; then
        mkdir -p "$BACKUP_DIR"
        log_info "创建备份目录: $BACKUP_DIR"
    fi
    
    # 生成备份文件名
    local backup_name="${server_type}_backup_$(date '+%Y%m%d_%H%M%S').tar.gz"
    local backup_path="$BACKUP_DIR/$backup_name"
    
    log_info "开始备份 $server_type 服务器..."
    
    # 创建备份归档
    if tar -czf "$backup_path" -C "$(dirname "$server_dir")" "$(basename "$server_dir")"; then
        log_info "成功创建备份: $backup_path"
        
        # 清理旧备份
        cleanup_old_backups "$server_type"
        
        return 0
    else
        log_error "备份创建失败"
        return 1
    fi
}

# 清理过期备份
cleanup_old_backups() {
    local server_type="$1"
    local retention_days="$BACKUP_RETENTION_DAYS"
    
    log_info "清理超过 $retention_days 天的 $server_type 旧备份..."
    
    find "$BACKUP_DIR" -name "${server_type}_backup_*.tar.gz" -type f -mtime +$retention_days -delete
    
    log_info "旧备份清理完成"
}

# ======= 通知函数 =======
# 发送更新通知
send_notification() {
    local server_type="$1"
    local old_version="$2"
    local new_version="$3"
    
    if [ "$ENABLE_NOTIFICATIONS" != "true" ]; then
        return 0
    fi
    
    local message="Minecraft $server_type 服务器已更新:\n旧版本: $old_version\n新版本: $new_version"
    
    log_info "发送更新通知..."
    
    case "$NOTIFICATION_METHOD" in
        "telegram")
            send_telegram_notification "$message"
            ;;
        "discord")
            send_discord_notification "$message"
            ;;
        "email")
            send_email_notification "$message"
            ;;
        *)
            log_warning "未知的通知方式: $NOTIFICATION_METHOD"
            ;;
    esac
}

# 发送Telegram通知
send_telegram_notification() {
    local message="$1"
    
    if [ -z "$TELEGRAM_BOT_TOKEN" ] || [ -z "$TELEGRAM_CHAT_ID" ]; then
        log_error "Telegram配置不完整，无法发送通知"
        return 1
    fi
    
    local api_url="${TELEGRAM_API_URL}${TELEGRAM_BOT_TOKEN}/sendMessage"
    curl -s -X POST "$api_url" -d chat_id="$TELEGRAM_CHAT_ID" -d text="$message" -d parse_mode="HTML" > /dev/null
    
    log_info "Telegram通知已发送"
}

# 发送Discord通知
send_discord_notification() {
    local message="$1"
    
    if [ -z "$DISCORD_WEBHOOK" ]; then
        log_error "Discord配置不完整，无法发送通知"
        return 1
    fi
    
    curl -s -X POST "$DISCORD_WEBHOOK" \
        -H "Content-Type: application/json" \
        -d "{\"content\":\"$message\"}" > /dev/null
    
    log_info "Discord通知已发送"
}

# 发送邮件通知
send_email_notification() {
    local message="$1"
    
    if [ -z "$EMAIL_TO" ] || [ -z "$EMAIL_FROM" ]; then
        log_error "邮件配置不完整，无法发送通知"
        return 1
    fi
    
    echo -e "$message" | mail -s "$EMAIL_SUBJECT" -r "$EMAIL_FROM" "$EMAIL_TO"
    
    log_info "邮件通知已发送"
}

# ======= 服务器管理函数 =======
# 检查服务器是否在运行
is_server_running() {
    local session_name="$1"
    
    # 检查screen会话是否存在
    if screen -list | grep -q "$session_name"; then
        return 0  # 服务器正在运行
    else
        return 1  # 服务器未运行
    fi
}

# 停止服务器
stop_server() {
    local session_name="$1"
    local stop_command="$2"
    
    if ! is_server_running "$session_name"; then
        log_info "服务器已经停止，无需操作"
        return 0
    fi
    
    log_info "正在停止服务器..."
    
    # 发送停止命令到screen会话
    screen -S "$session_name" -p 0 -X stuff "say 服务器将在10秒后停止进行更新...\n"
    sleep 5
    screen -S "$session_name" -p 0 -X stuff "say 服务器将在5秒后停止...\n"
    sleep 5
    screen -S "$session_name" -p 0 -X stuff "$stop_command\n"
    
    # 等待服务器完全停止
    local max_wait_time=60
    local wait_time=0
    while is_server_running "$session_name" && [ $wait_time -lt $max_wait_time ]; do
        sleep 1
        wait_time=$((wait_time + 1))
    done
    
    if is_server_running "$session_name"; then
        log_error "服务器未能在规定时间内停止，正在强制终止..."
        screen -S "$session_name" -X quit
        sleep 2
    fi
    
    log_info "服务器已停止"
    return 0
}

# 启动服务器
start_server() {
    local server_dir="$1"
    local session_name="$2"
    local start_command="$3"
    
    if is_server_running "$session_name"; then
        log_info "服务器已在运行中，无需启动"
        return 0
    fi
    
    log_info "正在启动服务器..."
    
    # 切换到服务器目录并在screen会话中启动服务器
    cd "$server_dir" && screen -dmS "$session_name" bash -c "$start_command"
    
    sleep 5
    
    if is_server_running "$session_name"; then
        log_info "服务器已成功启动"
        return 0
    else
        log_error "服务器启动失败"
        return 1
    fi
}

# ======= 下载工具函数 =======
# 安全下载文件
download_file() {
    local url="$1"
    local output_file="$2"
    
    # 提取文件名
    local filename=$(basename "$output_file")
    
    # 使用配置文件中的User-Agent
    local user_agent="$USER_AGENT"
    
    echo -e "\e[1;34m=====================================================\e[0m"
    echo -e "\e[1;32m正在下载: $url\e[0m"
    
    if command -v wget > /dev/null; then
        if wget --user-agent="$user_agent" -q --show-progress -O "$output_file" "$url"; then
            local file_size=$(du -h "$output_file" | cut -f1)
            echo -e "\e[1;32m下载完成: $filename (大小: $file_size)\e[0m"
            log_info "下载完成: $filename (大小: $file_size)"
            return 0
        else
            log_error "使用wget下载失败，尝试使用curl..."
            if command -v curl > /dev/null; then
                if curl -A "$user_agent" -L --progress-bar -o "$output_file" "$url"; then
                    local file_size=$(du -h "$output_file" | cut -f1)
                    echo -e "\e[1;32m下载完成: $filename (大小: $file_size)\e[0m"
                    log_info "下载完成: $filename (大小: $file_size)"
                    return 0
                else
                    log_error "使用curl下载失败"
                    return 1
                fi
            else
                log_error "未找到curl工具，无法继续下载"
                return 1
            fi
        fi
    elif command -v curl > /dev/null; then
        if curl -A "$user_agent" -L --progress-bar -o "$output_file" "$url"; then
            local file_size=$(du -h "$output_file" | cut -f1)
            echo -e "\e[1;32m下载完成: $filename (大小: $file_size)\e[0m"
            log_info "下载完成: $filename (大小: $file_size)"
            return 0
        else
            log_error "使用curl下载失败"
            return 1
        fi
    else
        log_error "未找到wget或curl工具，无法下载"
        return 1
    fi
}

# ======= 版本比较工具 =======
# 比较两个版本号
# 返回: 0=相等, 1=第一个大, 2=第二个大
compare_versions() {
    local version1="$1"
    local version2="$2"
    
    # 如果版本完全相同，返回0
    if [ "$version1" = "$version2" ]; then
        return 0
    fi
    
    # 将版本号分割为数组
    IFS='.' read -ra VER1 <<< "$version1"
    IFS='.' read -ra VER2 <<< "$version2"
    
    # 获取最大长度
    local max_length=$((${#VER1[@]} > ${#VER2[@]} ? ${#VER1[@]} : ${#VER2[@]}))
    
    # 逐位比较
    for ((i=0; i<max_length; i++)); do
        local v1=$((i < ${#VER1[@]} ? ${VER1[i]} : 0))
        local v2=$((i < ${#VER2[@]} ? ${VER2[i]} : 0))
        
        if [ "$v1" -gt "$v2" ]; then
            return 1  # 第一个版本大
        elif [ "$v1" -lt "$v2" ]; then
            return 2  # 第二个版本大
        fi
    done
    
    # 版本相同
    return 0
}

# ======= 初始化函数 =======
# 初始化
init() {
    # 确保临时目录和日志文件路径不为空
    if [ -z "$TEMP_DIR" ]; then
        TEMP_DIR="/tmp/minecraft_updater"
        log_warning "临时目录路径为空，使用默认值: $TEMP_DIR"
    fi
    
    if [ -z "$LOG_FILE" ]; then
        LOG_FILE="/var/log/minecraft_updater.log"
        log_warning "日志文件路径为空，使用默认值: $LOG_FILE"
    fi
    
    # 检查目录路径是否有效
    if [[ "$TEMP_DIR" != /* ]]; then
        # 如果不是绝对路径，添加当前目录前缀
        if [[ "$TEMP_DIR" == ./* ]]; then
            TEMP_DIR="$(pwd)/${TEMP_DIR:2}"
        else
            TEMP_DIR="$(pwd)/$TEMP_DIR"
        fi
        log_warning "临时目录不是绝对路径，已转换为: $TEMP_DIR"
    fi
    
    if [[ "$LOG_FILE" != /* ]]; then
        # 如果不是绝对路径，添加当前目录前缀
        if [[ "$LOG_FILE" == ./* ]]; then
            LOG_FILE="$(pwd)/${LOG_FILE:2}"
        else
            LOG_FILE="$(pwd)/$LOG_FILE"
        fi
        log_warning "日志文件不是绝对路径，已转换为: $LOG_FILE"
    fi
    
    # 检查并创建临时目录
    if [ ! -d "$TEMP_DIR" ]; then
        mkdir -p "$TEMP_DIR"
        log_info "已创建临时目录: $TEMP_DIR"
    else
        # 清空临时目录
        rm -rf "${TEMP_DIR:?}"/*
    fi
    
    # 检查并创建日志文件所在目录
    local log_dir=$(dirname "$LOG_FILE")
    if [ ! -d "$log_dir" ]; then
        mkdir -p "$log_dir"
        log_info "已创建日志目录: $log_dir"
    fi
    
    # 确保日志文件存在
    touch "$LOG_FILE" 2>/dev/null || {
        log_error "无法创建日志文件 $LOG_FILE，可能是权限问题"
        log_warning "尝试在当前目录创建日志文件"
        LOG_FILE="./minecraft_updater.log"
        touch "$LOG_FILE"
    }
    
    # 检查screen是否安装
    if ! command -v screen > /dev/null; then
        log_error "未找到screen命令，请安装screen工具"
        exit 1
    fi
}

# 注意：现在在load_config的最后调用init，所以这里注释掉
# init  # 这行会在配置加载后调用，确保变量已经设置

# 检查并安装必要的依赖项
# 注意：此功能已移至minecraft_updater.sh主脚本中
# check_and_install_dependencies() {
#     # 检查是否具有sudo权限
#     if command -v sudo > /dev/null && sudo -n true 2>/dev/null; then
#         HAS_SUDO=true
#     else
#         HAS_SUDO=false
#         log_warning "没有sudo权限，如果需要安装依赖，可能会失败"
#     fi
#     
#     # 检查jq
#     if ! command -v jq > /dev/null; then
#         log_warning "未找到jq命令，尝试安装..."
#         if [ "$HAS_SUDO" = true ]; then
#             if command -v apt-get > /dev/null; then
#                 sudo apt-get update && sudo apt-get install -y jq
#             elif command -v yum > /dev/null; then
#                 sudo yum install -y jq
#             elif command -v dnf > /dev/null; then
#                 sudo dnf install -y jq
#             else
#                 log_error "无法确定包管理器，请手动安装jq"
#                 return 1
#             fi
#         else
#             log_error "没有sudo权限，无法安装jq，请手动安装"
#             return 1
#         fi
#     fi
#     
#     # 检查curl或wget
#     if ! command -v curl > /dev/null && ! command -v wget > /dev/null; then
#         log_warning "未找到curl或wget命令，尝试安装..."
#         if [ "$HAS_SUDO" = true ]; then
#             if command -v apt-get > /dev/null; then
#                 sudo apt-get update && sudo apt-get install -y curl
#             elif command -v yum > /dev/null; then
#                 sudo yum install -y curl
#             elif command -v dnf > /dev/null; then
#                 sudo dnf install -y curl
#             else
#                 log_error "无法确定包管理器，请手动安装curl或wget"
#                 return 1
#             fi
#         else
#             log_error "没有sudo权限，无法安装curl或wget，请手动安装"
#             return 1
#         fi
#     fi
#     
#     # 检查unzip
#     if ! command -v unzip > /dev/null; then
#         log_warning "未找到unzip命令，尝试安装..."
#         if [ "$HAS_SUDO" = true ]; then
#             if command -v apt-get > /dev/null; then
#                 sudo apt-get update && sudo apt-get install -y unzip
#             elif command -v yum > /dev/null; then
#                 sudo yum install -y unzip
#             elif command -v dnf > /dev/null; then
#                 sudo dnf install -y unzip
#             else
#                 log_error "无法确定包管理器，请手动安装unzip"
#                 return 1
#             fi
#         else
#             log_error "没有sudo权限，无法安装unzip，请手动安装"
#             return 1
#         fi
#     fi
#     
#     return 0
# } 